package de.hft_stuttgart.dsa.ctt.processing.genetic;

import java.util.ArrayList;
import java.util.List;

import de.hft_stuttgart.dsa.ctt.model.CourseAssignmentMatrix;
import de.hft_stuttgart.dsa.ctt.model.CourseCompetitionMatrix;
import de.hft_stuttgart.dsa.ctt.model.ProblemInstance;
import de.hft_stuttgart.dsa.ctt.processing.IAssigner;
import de.hft_stuttgart.dsa.ctt.processing.Preprocessor;
import de.hft_stuttgart.dsa.ctt.processing.TimeslotCourseAssigner;

/**
 * @author Eduard Tudenhoefner
 */
public class Genetecist implements IGenetecist {
	private static final int INITIAL_POPULATION_SIZE = 200;
	private static final int NUMBER_OF_PARENTS = 2;
	private static final int NUMBER_OF_GENERATIONS = 100;
	private ProblemInstance problemInstance;

	public Genetecist(ProblemInstance problemInstance) {
		if (null == problemInstance) {
			throw new RuntimeException("The problem instance must not be null.");
		}

		this.problemInstance = problemInstance;
	}

	/**
	 * {@inheritDoc}
	 */
	public void perform() {
		List<CourseAssignmentMatrix> initialPopulation = createInitialPopulation();

		// perform genetic algorithm until certain number of generations are
		// reached
		int createdGenerations = 0;
		while (createdGenerations <= NUMBER_OF_GENERATIONS) {
			List<CourseAssignmentMatrix> parentsForReproduction = new Selector().selectParentsForReproduction(NUMBER_OF_PARENTS, initialPopulation, problemInstance);
			List<CourseAssignmentMatrix> newPopulation = new Reproducer().createNewPopulation(parentsForReproduction);
			createdGenerations++;
		}
	}

	/**
	 * @return An initial population of size {@value #INITIAL_POPULATION_SIZE}.
	 */
	private List<CourseAssignmentMatrix> createInitialPopulation() {
		List<CourseAssignmentMatrix> initialPopulation = new ArrayList<CourseAssignmentMatrix>();

		while (initialPopulation.size() <= INITIAL_POPULATION_SIZE) {
			CourseCompetitionMatrix courseCompetitionMatrix = new CourseCompetitionMatrix(problemInstance.getRooms(), problemInstance.getPeriods(), problemInstance.getNumberOfCourses());
			Preprocessor preprocessor = new Preprocessor(problemInstance, courseCompetitionMatrix);
			preprocessor.processCourseCompetitionMatrix();

			IAssigner timeslotCourseAssigner = new TimeslotCourseAssigner(problemInstance, courseCompetitionMatrix);
			CourseAssignmentMatrix courseAssignmentMatrix = timeslotCourseAssigner.assignCoursesToMatrix();

			if (null != courseAssignmentMatrix) {
				initialPopulation.add(courseAssignmentMatrix);
			}
		}
		return initialPopulation;
	}

}
